package com.onpositive.notes.services;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import com.onpositive.notes.model.INote;
import com.onpositive.notes.model.INoteEntry;
import com.onpositive.notes.model.ITemplate;

public class BasicNoteRegistry implements INoteRegistry {
	
	private static final long serialVersionUID = 2359662506867485723L;
	
	private static BasicNoteRegistry instance ;
	
	public static BasicNoteRegistry getInstance(){
		if( instance == null )
			instance = new BasicNoteRegistry() ;
		
		return instance ;
	}
	
	public static void disposeInstance(){
		instance = null ;
	}
	
	protected BasicNoteRegistry() {
		super();
	}	
	
	ArrayList<INote> noteList = new ArrayList<INote>() ;
	ArrayList<INoteEntry> entryList = new ArrayList<INoteEntry>() ;
	HashMap<Integer, INote> noteMap = new HashMap<Integer, INote>() ;
	HashMap<Integer, INoteEntry> entryMap = new HashMap<Integer, INoteEntry>() ;
	private int vacantNoteId = 0 ;
	private int vacantEntryId = 0 ;
	private boolean isInitialized = false ;

	@Override
	public List<INote> getAllNotes() {
		return noteList ;
	}

	@Override
	public INote getNote(int id) {
		return noteMap.get(id);
	}

	@Override
	public ITemplate getTemplate(int id) {
		INoteEntry entry = entryMap.get(id);
		return entry instanceof ITemplate ? (ITemplate)entry : null ;
	}

	@Override
	public int registerNote(INote note) {
		
		int noteId = vacantNoteId++;
		note.setId(noteId) ;
		noteMap.put(noteId, note) ;
		noteList.add(note) ;
		
		for( INoteEntry entry : note.getEntries() ){
			
			int entryId = vacantEntryId++ ;
			entry.setId(entryId) ;
			entryMap.put(entryId, entry) ;
			entryList.add(entry) ;
		}
		
		for( INoteEntry entry : note.getEntries() ){
			
			if( entry instanceof ITemplate ){
				((ITemplate)entry).apply() ;
			}
		}
		return noteId ;
	}

	@Override
	public boolean isIinitialized() {
		return isInitialized ;
	}
	
	public static void loadInstance(String path){
		
		File f = new File( path ) ;
		if(!f.exists())
			return ;
		
		ObjectInputStream ois;
		try {
			ois = new ObjectInputStream( new FileInputStream(f));
			Object readObject = ois.readObject();
			ois.close() ;
			instance = (BasicNoteRegistry) readObject ;			
			instance.setInitialized(true) ;
		} catch (StreamCorruptedException e) {
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}		
	} ;

	public static void saveInstance(String path){
		
		File f = new File( path ) ;
		if(f.exists())
			f.delete() ;
		
		try {
			f.createNewFile() ;
			ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(f)) ;
			oos.writeObject( instance ) ;
			oos.close() ;
			
		} catch (IOException e) {
			e.printStackTrace();
		}		
	}

	@Override
	public INoteEntry getNoteEntry(int id) {
		return entryMap.get(id);
	} ;
	
	private void setInitialized(boolean b) {
		this.isInitialized = b ;		
	}

	@Override
	public boolean unRegisterNote(INote note) {
		
		int ind = noteList.indexOf(note) ;
		if( ind < 0 )
			return false ;
		
		noteList.remove(ind) ;
		noteMap.remove( note.getId() ) ;
		
		for( INoteEntry entry : note.getEntries() ){
			
			ind = entryList.indexOf(entry) ;
			if( ind < 0 )
				continue ;
			
			entryList.remove(ind) ;
			entryMap.remove( entry.getId() ) ;
		}
		
		for( INoteEntry entry : note.getEntries() ){
			if( entry instanceof ITemplate )
				((ITemplate)entry).cancel() ;
		}
		
		return true ;
	}


}
